/**
 * This file is part of the NatCrackerToolbox.
 * 
 * Copyright (C) 2009 - 2011 Peerialism Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 **/
package com.peerialism.natcracker.discovery;

import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.log4j.Logger;

import com.peerialism.natcracker.discovery.jstun.attribute.DiscoveryInfo;

public class DiscoveryThread extends Thread {

	private static final Logger log = Logger.getLogger(DiscoveryThread.class);

	final InetAddress interfaceAddress;
	DiscoveryInfo info = null;
	private final List<DiscoveryInfoBehave> infoSet;
	private final List<String> STUNservers;
//	private int bindPort;

	private DatagramSocket sock;

	public DiscoveryThread(DatagramSocket sock, InetAddress interfaceAddress, List<DiscoveryInfoBehave> infos, String[] stunServers) {
		infoSet = infos;
		this.sock = sock;
		this.interfaceAddress = interfaceAddress;

		STUNservers = new ArrayList<String>(Arrays.asList(stunServers));
		
		//Collections.shuffle(STUNservers, new Random(interfaceAddress.hashCode()));
	}

	@Override
	public void run() {
		boolean discoverySucceded = false;

		int count = 0;
		while (!discoverySucceded) {

			if (count == STUNservers.size()) {
				log.info("discovery failed");
				synchronized (infoSet) {
					DiscoveryInfoBehave info = new DiscoveryInfoBehave(interfaceAddress);
					info.setBlockedUDP();
					infoSet.add(info);
					infoSet.notify();
				}
				break;
			}
			try {

				log.debug("Start STUN test for interface: " + interfaceAddress);
				log.debug("using STUN server: " + STUNservers.get(count));

				// DiscoveryTest test = new DiscoveryTest(interfaceAddress, STUNservers.get(count));
				// info = test.test();
				// if (!info.getGatewayType().equals(GatewayType.UdpBlockingFirewall)) {
				DiscoveryTest testBehave = new DiscoveryTest(interfaceAddress, STUNservers.get(count));
				DiscoveryInfoBehave info = testBehave.test(sock);
				// }

				synchronized (infoSet) {
					if (!info.isError()) {
						infoSet.add(info);
					}
					infoSet.notify();
				}

			} catch (UnknownHostException e) {
				log.warn("STUN Server " + e.getMessage() + " is not available");
				count++;

				continue;
			} catch (Exception e) {
				log.error("Error in STUN discovery for interface: " + interfaceAddress + " and STUN server: " + STUNservers.get(count) + " mapping could be already taken", e);
				count++;
				continue;
			}
			discoverySucceded = true;
		}

	}
}
